package org.nt4b.schemadoc.webgui.service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.nt4b.schemadoc.core.DAOFactory;
import org.nt4b.schemadoc.core.dao.SchemaDocDAO;
import org.nt4b.schemadoc.core.dom.SchemaComments;
import org.nt4b.schemadoc.core.dom.Table;
import org.nt4b.schemadoc.webgui.ConnectionConfiguration;
import org.nt4b.schemadoc.webgui.ConnectionProperties;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.util.StringUtils;


public class CommentsServiceImpl implements Serializable, CommentsService {
    private static final long serialVersionUID = 6881180288607970082L;
    
    protected Logger logger = Logger.getLogger(CommentsServiceImpl.class);
    
    private TransactionalCommentsService transactionalCommentsService;
    private DataSource dataSource;
    
    public DataSource getDataSource() {
        return dataSource;
    }
    
    @Required
    public void setDataSource(final DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    public TransactionalCommentsService getTransactionalCommentsService() {
        return transactionalCommentsService;
    }
    
    @Required
    public void setTransactionalCommentsService(final TransactionalCommentsService transactionalCommentsService) {
        this.transactionalCommentsService = transactionalCommentsService;
    }
    
    @Override
    public List<Table> loadSchemaComments(final ConnectionConfiguration connectionConfiguration) {
        final String schemaName = getSchemaName(connectionConfiguration);
        final SchemaDocDAO dao = getDAO(connectionConfiguration);
        final List<Table> tables = transactionalCommentsService.loadSchemaComments(dao, schemaName);
        
        final List<Table> filteredResult = new ArrayList<Table>();
        for (final Table table : tables) {
            if (!StringUtils.startsWithIgnoreCase(table.getName(), "BIN$")) {
                filteredResult.add(table);
            }
        }
        
        logger.info("Got schema comments");
        return filteredResult;
    }
    
    @Override
    public List<Table> loadTablesComments(final ConnectionConfiguration connectionConfiguration) {
        final String schemaName = getSchemaName(connectionConfiguration);
        final SchemaDocDAO dao = getDAO(connectionConfiguration);
        final List<Table> tables = transactionalCommentsService.loadTableComments(dao, schemaName);
        
        final List<Table> filteredResult = new ArrayList<Table>();
        for (final Table table : tables) {
            // Filter all recycled tables
            
            if (!StringUtils.startsWithIgnoreCase(table.getName(), "BIN$")) {
                filteredResult.add(table);
            }
        }
        
        logger.info("Got comments of all tables");
        return filteredResult;
    }
    
    @Override
    public Table loadColumnComments(final ConnectionConfiguration connectionConfiguration, final String tableName) {
        final String schemaName = getSchemaName(connectionConfiguration);
        final SchemaDocDAO dao = getDAO(connectionConfiguration);
        final Table table = transactionalCommentsService.loadColumnComments(dao, schemaName, tableName);
        
        logger.info("Got comments of table " + tableName);
        return table;
    }
    
    @Override
    public void saveSchemaComments(final ConnectionConfiguration connectionConfiguration, final SchemaComments schemaComments) {
        final SchemaDocDAO dao = getDAO(connectionConfiguration);
        transactionalCommentsService.saveSchemaComments(dao, schemaComments);
    }
    
    @Override
    public void saveTableComments(final ConnectionConfiguration connectionConfiguration, final List<Table> tables) {
        final SchemaDocDAO dao = getDAO(connectionConfiguration);
        transactionalCommentsService.saveTableComments(dao, tables);
        logger.info("table comments saved");
    }
    
    @Override
    public void saveColumnComments(final ConnectionConfiguration connectionConfiguration, final Table table) {
        final List<Table> tables = new ArrayList<Table>();
        tables.add(table);
        
        final SchemaDocDAO dao = getDAO(connectionConfiguration);
        transactionalCommentsService.saveTableComments(dao, tables);
        
        logger.info("column comments saved");
    }
    
    /**
     * Prepare SchemaDocDAO  for a given connection configuration.
     * 
     * @param connectionConfiguration
     * @return SchemaDocDAO
     */
    private SchemaDocDAO getDAO(final ConnectionConfiguration connectionConfiguration) {
        
        final String url;
        final String username;
        final String password;
        
        final ConnectionProperties selectedConnectionProperties = connectionConfiguration.getConnectionProperties();
        if (selectedConnectionProperties != null) {
            url = selectedConnectionProperties.getUrl();
            username = selectedConnectionProperties.getUsername();
            password = selectedConnectionProperties.getPassword();
        } else {
            url = connectionConfiguration.getUrl();
            username = connectionConfiguration.getUsername();
            password = connectionConfiguration.getPassword();
        }
        
        logger.info("Prepare DAO for: " + url + ", user: " + username);
        
        final SchemaDocDAO dao = DAOFactory.getDAO(dataSource, url, username, password);
        
        return dao;
    }
    
    /**
     * Internal function for extracting selected schema name from connection configuration
     * 
     * @param connectionConfiguration
     * @return
     */
    private String getSchemaName(final ConnectionConfiguration connectionConfiguration) {
        final ConnectionProperties selectedConnectionProperties = connectionConfiguration.getConnectionProperties();
        if (selectedConnectionProperties != null) {
            return selectedConnectionProperties.getSchemaName();
        }        
        return connectionConfiguration.getUrl();
    }
    
}
